#ifndef _COREAPPLICATION_H_
#define _COREAPPLICATION_H_

#include <SECore/EventLoop.h>
#include <memory>
#include <SECore/Window.h>
#include <list>
#include <SECore/Layer.h>
#include <SECore/Descriptor.h>
#include <SECore/OrderedMap.h>

namespace SEngine
{
    class CoreApplication : public AnyDescriptor
    {
    public:
        CoreApplication();
        virtual ~CoreApplication();
        virtual void Init();
        void Exec();
        static CoreApplication & App();
        static std::string ApplicationCwd();

        void SetWindow(std::unique_ptr<Window> && window);
        std::unique_ptr<Window> & GetWindow();

        void PushFrontLayer(const std::string & name, std::unique_ptr<Layer> && layer);
        void PushFrontLayer(std::unique_ptr<Layer> && layer);
        void PushBackLayer(const std::string & name, std::unique_ptr<Layer> && layer);
        void PushBackLayer(std::unique_ptr<Layer> && layer);
        std::optional<std::reference_wrapper<Layer>> GetLayer(const std::string & name);
        void RemoveLayer(const std::string & name);
        void SendTask(EventLoop<CoreApplication&>::Task && task, EventLoop<CoreApplication&>::TaskMode mode = EventLoop<CoreApplication&>::TaskMode::Immediately) { m_eventLoop.SendTask(std::move(task), mode); }
        
        EventLoop<CoreApplication&> & GetEventLoop() { return m_eventLoop; }

    private:
        void Update();
        void OnEvent(EventPtr);
        void OnQuitEvent(QuitEventPtr);
    
    protected:
        EventLoop<CoreApplication&> m_eventLoop;
        std::unique_ptr<Window> m_window;
        OrderedMap<std::string, std::unique_ptr<Layer>> m_layers;
        inline static std::chrono::steady_clock::time_point s_lastTime;
        static CoreApplication * s_app;
    };
} // namespace SEngine


#endif